package com.xz.supplierOrder.service.impl;

import com.xz.common.exception.ServiceException;
import com.xz.common.utils.DateUtils;
import com.xz.common.validation.SituationGroup;
import com.xz.common.validation.ValidatorUtils;
import com.xz.supplierOrder.domain.SupplierOrder;
import com.xz.supplierOrder.domain.SupplierOrderDetail;
import com.xz.supplierOrder.domain.SupplierOrderDetailRecord;
import com.xz.supplierOrder.dto.SupplierOrderDto;
import com.xz.supplierOrder.enums.SupplierOrderExchangeMethodEnum;
import com.xz.supplierOrder.enums.SupplierOrderStatusEnum;
import com.xz.supplierOrder.service.ISupplierOrderDetailRecordService;
import com.xz.supplierOrder.service.ISupplierOrderDetailService;
import com.xz.supplierOrder.service.ISupplierOrderProductService;
import com.xz.supplierOrder.service.ISupplierOrderTypeProcessorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;

/**
 * 贸易中间商-发货单处理类
 */
@Service("supplierExchangeOrderServiceImpl")
public class SupplierExchangeOrderServiceImpl implements ISupplierOrderTypeProcessorService {

  @Autowired
  private ISupplierOrderDetailService supplierOrderDetailService;
  @Resource
  private ISupplierOrderProductService supplierOrderProductService;
  @Autowired
  private ISupplierOrderDetailRecordService supplierOrderDetailRecordService;

  /**
   * 校验单据
   * @param supplierOrder （贸易中间商）单据商品
   */
  @Override
  public void verifyFields(SupplierOrderDto supplierOrder) {

    // 是否待提交的数据（在上游方法中会查询目前数据库的状态，并且填充到beforeStatus字段中，这里可判断出在此之前是否为未提交的订单数据）
    boolean isSubmitStatus = SupplierOrderStatusEnum.TO_BE_DELIVERY.eq(supplierOrder.getBeforeStatus());
    if(isSubmitStatus){
      // 是否先退后换（根据换货方式的值来判断）
      boolean isReturnFirst = SupplierOrderExchangeMethodEnum.RETURN_FIRST.getType() == supplierOrder.getExchangeMethod();
      //如果是新提交的数据，则只校验其中一个。要不是先换，就是先退,二者前端只会传一个。
      check(supplierOrder,isReturnFirst,!isReturnFirst);
    }else{
      //如果不是新提交的数据，则只校验全部
      check(supplierOrder,true,true);
    }
  }

  /**
   * 检查订单字段
   * @param supplierOrder 订单
   * @param checkReturn 是否检查退货信息
   * @param checkDelivery 是否检查换货信息
   */
  private void check(SupplierOrderDto supplierOrder,boolean checkReturn,boolean checkDelivery) {
    if(checkReturn && CollectionUtils.isEmpty(supplierOrder.getReturnDetails())){
      throw new ServiceException("收货信息不能为空");
    }

    if(checkDelivery){
      if(CollectionUtils.isEmpty(supplierOrder.getDeliveryDetails())){
        throw new ServiceException("换货信息不能为空");
      }
      // 校验发货单相关字段
      try {
        ValidatorUtils.validate(supplierOrder, SituationGroup.A.class);
      } catch (ConstraintViolationException ex) {
        String message = new ArrayList<>(ex.getConstraintViolations()).get(0).getMessage();
        throw new ServiceException(message);
      }
    }
  }

  /**
   * 提交单据
   *
   * @param supplierOrder
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void submitOrder(SupplierOrder supplierOrder) {

    // 是否先退后换（根据换货方式的值来判断）
    boolean isReturnFirst = SupplierOrderExchangeMethodEnum.RETURN_FIRST.getType() == supplierOrder.getExchangeMethod();
    // 是否待提交的数据（在上游方法中会查询目前数据库的状态，并且填充到beforeStatus字段中，这里可判断出在此之前是否为未提交的订单数据）
    boolean isSubmitStatus = SupplierOrderStatusEnum.TO_BE_DELIVERY.eq(supplierOrder.getBeforeStatus());
    // 数据类型（1-发货,2-退货），先默认为 1-发货
    Integer dataType = 1;
    // 换货的流程只有先退后换，先换后退两种,结合当前在此之前的数据状态，可用得出如果是要退货操作，必定会满足以下两个条件，
    // 第一种：退货方式为先退后换，旧状态为0；
    // 第二种：退货方式为先换后退(即不为先退后换)，旧的状态不为0；
    if(isReturnFirst && isSubmitStatus || !isReturnFirst && !isSubmitStatus){
      dataType = 2;
    }

    //查询单据id对应类型的（1-发货,2-退货）商品数据
    List<SupplierOrderDetail> details = supplierOrderDetailService.selectByOrderIdAndDataType(supplierOrder.getId(),dataType);
    if (CollectionUtils.isEmpty(details)) {
      return;
    }

    //根据数据类型（1-发货,2-退货）来决定如何扣减库存
    if(1 == dataType){
      // 如果发货数据，那么要判断是先退，还是先换。
      // 如果是先退，那就把状态改为2（已换货）
      // 如果是先换，那就把状态改为6（已换货待收货）
      if(isReturnFirst){
        supplierOrder.setOrderStatus(SupplierOrderStatusEnum.SUBMITTED.getStatus());
      }else{
        supplierOrder.setOrderStatus(SupplierOrderStatusEnum.EXCHANGE_AWAITING_RECEIPT.getStatus());
      }
      // 21.贸易中间商换货单（换货）
      supplierOrderProductService.deliverySupplierOrder(supplierOrder, details, 21);
    }else {
      // 如果退货数据，那么要判断是先退，还是先换。
      // 如果是先退，那就把状态改为5（已换货待收货）
      // 如果是先换，那就把状态改为2（已换货）
      if(isReturnFirst){
        supplierOrder.setOrderStatus(SupplierOrderStatusEnum.RECEIVED_AWAITING_EXCHANGE.getStatus());
      }else{
        supplierOrder.setOrderStatus(SupplierOrderStatusEnum.SUBMITTED.getStatus());
      }
      // 20.贸易中间商换货单（退货）
      supplierOrderProductService.returnSupplierOrder(supplierOrder, details, 20);
    }

  }

  /**
   * 冲红单据
   *
   * @param supplierOrder
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void reversalOrder(SupplierOrder supplierOrder) {

    // 换货单有三种情况下可以冲红，分别是状态2,5,6;
    // 不管是那种，只要检索出出入库记录，就允许红冲

    // 查询对应的贸易中间商订单商品出库记录
    List<SupplierOrderDetailRecord> deliveryRecords = supplierOrderDetailRecordService.getByOrder(
      supplierOrder.getId(), null, 1);

    if(!CollectionUtils.isEmpty(deliveryRecords)){
      // 把详情塞入出库记录中
      supplierOrderDetailService.setRecordDetail(supplierOrder, deliveryRecords);
      // 开始冲红操作 23.贸易中间商换货单（换货冲红）
      supplierOrderProductService.reversalOrderForDelivery(supplierOrder,deliveryRecords, 23);
    }

    // 查询对应的贸易中间商订单商品出库记录
    List<SupplierOrderDetailRecord> returnRecords = supplierOrderDetailRecordService.getByOrder(
      supplierOrder.getId(), null, 2);
    if(!CollectionUtils.isEmpty(returnRecords)){
      // 把详情塞入出库记录中
      supplierOrderDetailService.setRecordDetail(supplierOrder, returnRecords);
      // 开始冲红操作 22.贸易中间商换货单（退货冲红）
      supplierOrderProductService.reversalOrderForReturn(supplierOrder,returnRecords, 22);
    }

    // 更新冲红状态
    supplierOrderProductService.updateForReversal(supplierOrder);
  }
}
